//
// Created By: Xiaofeng.Gu 2021/05/18
//
#include "cybertron/core/AlarmClient.hpp"
#include "cybertron/core/UtilUrlRequest.hpp"
#include "cybertron/core/JsonReader.hpp"
#include "cybertron/core/UtilTime.hpp"
#include "cybertron/core/Log.hpp"
#include "cybertron/core/SimOneEnv.hpp"
#include "cybertron/node/StartupArguments.hpp"
#include "cybertron/core/SimOneServerInfo.hpp"
#include <thread>

#define DURATION_SECONDS 30


CYBERTRON_BEGIN


CybertronCoreAPI std::shared_ptr<AlarmClient> gAlarmClient = nullptr;
AlarmClient::AlarmClient() : mInitialized(false)
{
	mInitialized = false;
	mStop = false;
}

void AlarmClient::Initialize(unsigned int connectMaxSeconds, long alarmQueueMaxCount)
{
	SimOneServerInfo::GetInstance().Init();
	SimOneServerInfo::AlarmServerInfo serverInfo;
	SimOneServerInfo::GetInstance().getAlarmServerInfo(&serverInfo);
	Create(serverInfo.serverAddr, std::to_string(serverInfo.port), connectMaxSeconds, alarmQueueMaxCount);
}

void AlarmClient::Create(const std::string& ip, const std::string& port, unsigned int connectMaxSeconds, long alarmQueueMaxCount)
{
	mAlarmServerIp = ip;
	mAlarmServerPort = port;
	mConnectMaxSeconds = connectMaxSeconds;
	mAlarmQueueMaxCount = alarmQueueMaxCount;

	if (!mInitialized)
	{
		mInitialized = true;
		mRunningThread = std::thread(&AlarmClient::Run, this);
	}
}

bool AlarmClient::PushAlarmMessage(nlohmann::json& messageBody)
{
	if (mAlarmQueue.size() < mAlarmQueueMaxCount)
	{
		mAlarmQueue.push_back(messageBody);
		return true;
	}
	else
	{
		return false;
	}
}

void AlarmClient::Run()
{
	nlohmann::json alarmMessage;
	while (true)
	{
		if (mStop == true)
		{
			break;
		}

		if (mAlarmQueue.pop_swap_front(alarmMessage))
		{
			bool succeed = true;
			std::string exceptionError;
			std::string result;
			succeed = SendAlarmMessage("/v1/alarm/send", alarmMessage, result, exceptionError);
			if (!succeed)
			{
				logError("fail to send alarm message : %s", result.c_str());
			}
		}

		std::this_thread::sleep_for(std::chrono::milliseconds(10));
	}
}

void AlarmClient::Destroy()
{
	mStop = true;
	mRunningThread.join();
}

bool AlarmClient::SendAlarmMessage(const std::string& url, nlohmann::json& messageBody, std::string& result, std::string& error)
{
	bool succeed = true;
	UtilTime::millisecondsUpdate();
	unsigned int now = UtilTime::millisecondsCurrent();
	while (true)
	{
		try
		{
			result = UtilUrlRequest::PostUrl("http://" + mAlarmServerIp + ":" + mAlarmServerPort + "" + url, messageBody.dump());
			succeed = true;
			break;
		}
		catch (const UtilUrlRequest::TException& ex)
		{
			error = ex.what();
			succeed = false;
		}

		UtilTime::millisecondsUpdate();
		if ((UtilTime::millisecondsCurrent() - now) / 1000 > mConnectMaxSeconds)
		{
			break;
		}

		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
		logInfo(">>>>>>>>>>>>>>>>>connecting %s:%s\n", mAlarmServerIp.c_str(), mAlarmServerPort.c_str());
	}

	if (succeed == false)
	{
		logInfo(">>>>>>>>>>>>>>>>>fail to connect %s:%s\n", mAlarmServerIp.c_str(), mAlarmServerPort.c_str());
	}

	return succeed;
}

CybertronCoreAPI void AlarmSetup(unsigned int connectMaxSeconds, long alarmQueueMaxCount)
{
	if (gAlarmClient == nullptr)
	{
		gAlarmClient = std::make_shared<AlarmClient>();

		gAlarmClient->Initialize(connectMaxSeconds, alarmQueueMaxCount);
	}
}

CybertronCoreAPI bool AlarmSendMessage(
	AlarmClient::AlarmLevel level,
	int errorCode,
	const std::string& nodeType,
	const std::string& nodeId,
	const std::string& alarmDescription)
{
	std::string timestamp = UtilTime::getLocalTimeStringForPrint24HourFormat();
	int levelValue = (int)level;

	SimOneEnv::SimOneCloudEnvInfo cloundEnvInfo;
	SimOneEnv::GetInstance().GetCloundEnvInfo(cloundEnvInfo);
	
	nlohmann::json messageBody;
	messageBody["level"] = levelValue;
	messageBody["errorCode"] = std::to_string(errorCode);
	messageBody["description"] = alarmDescription;
	messageBody["timestamp"] = timestamp;
	messageBody["nodeType"] = nodeType;
	messageBody["nodeId"] = nodeId;
	messageBody["podName"] = cloundEnvInfo.PodName;
	messageBody["podNamespace"] = cloundEnvInfo.PodNameSpace;

	if (gAlarmClient != nullptr)
	{
		return gAlarmClient->PushAlarmMessage(messageBody);
	}

	return false;
}

CybertronCoreAPI void GetAlarmServerConfig()
{
	//10.66.9.152 20000
	//Read environment variables of Alarm config
	//char *alarmServerIp = theStartupArguments().getParamValue("ALARM_SERVER_IP");//getenv("LOG_SERVER_IP");
	//if (alarmServerIp != nullptr) {
	//	char *alarmServerPort = theStartupArguments().getParamValue("ALARM_SERVER_PORT");
	//	int connectMaxSeconds = atoi(theStartupArguments().getParamValue("ALARM_SERVER_PORT"));
	//	int alarmQueueMaxCount = atoi(theStartupArguments().getParamValue("ALARM_SERVER_PORT"));
	//	AlarmSetup(alarmServerIp, alarmServerPort, connectMaxSeconds, alarmQueueMaxCount);
	//}
	// "10.66.9.152", "20000"
	AlarmSetup();
}

CYBERTRON_END